using System;
using System.Collections.Generic;

namespace CLELCore.Assembly.CLELInstructions
{
	public static class CLELInstructionTools
	{
		public static int CodeSize(List<CLELInstruction> code)
		{
			int code_size = 0;
			if(code != null)
			{
				int i,end = code.Count;
				for(i = 0;i < end;i++)
				{
					code_size += code[i].Length;
				}
			}
			return code_size;
		}
		
		public static uint NextLocalNum(List<CLELInstruction> code)
		{
			if(code == null)
				throw new ArgumentException("Code cannot be null");
			uint ret = 0;
			bool any_locals = false;
			int i,end = code.Count;
			uint loc;
			CLELInstruction inst;
			byte opcode,fun;
			Ldloc ldloc;
			Ldloca ldloca;
			Ldlocas ldlocas;
			Ldlocs ldlocs;
			Stloc stloc;
			Stlocs stlocs;
			ObjectModel om;
			for(i = 0;i < end;i++)
			{
				inst = code[i];
				opcode = inst.Opcode;
				if(opcode == CLELOpcode.OBJECTMODEL)
				{
					om = (ObjectModel)inst;
					fun = om.Function;
					if(fun == CLELOpcode.LDLOC)
					{
						any_locals = true;
						ldloc = (Ldloc)inst;
						loc = (uint)ldloc.Local;
						if(ret < loc)
							ret = loc;
					}
					else if(fun == CLELOpcode.LDLOCA)
					{
						any_locals = true;
						ldloca = (Ldloca)inst;
						loc = (uint)ldloca.Local;
						if(ret < loc)
							ret = loc;
					}
					else if(fun == CLELOpcode.STLOC)
					{
						any_locals = true;
						stloc = (Stloc)inst;
						loc = (uint)stloc.Local;
						if(ret < loc)
							ret = loc;
					}
				}
				else if(opcode == CLELOpcode.LDLOC0 || opcode == CLELOpcode.STLOC0)
				{
					//starts at 0
					any_locals = true;
				}
				else if(opcode == CLELOpcode.LDLOC1 || opcode == CLELOpcode.STLOC1)
				{
					any_locals = true;
					if(ret < 1)
						ret = 1;
				}
				else if(opcode == CLELOpcode.LDLOC2 || opcode == CLELOpcode.STLOC2)
				{
					any_locals = true;
					if(ret < 2)
						ret = 2;
				}
				else if(opcode == CLELOpcode.LDLOC3 || opcode == CLELOpcode.STLOC3)
				{
					any_locals = true;
					if(ret < 3)
						ret = 3;
				}
				else if(opcode == CLELOpcode.LDLOCAS)
				{
					any_locals = true;
					ldlocas = (Ldlocas)inst;
					loc = (uint)ldlocas.Local;
					if(ret < loc)
						ret = loc;
				}
				else if(opcode == CLELOpcode.LDLOCS)
				{
					any_locals = true;
					ldlocs = (Ldlocs)inst;
					loc = (uint)ldlocs.Local;
					if(ret < loc)
						ret = loc;
				}
				else if(opcode == CLELOpcode.STLOCS)
				{
					any_locals = true;
					stlocs = (Stlocs)inst;
					loc = (uint)stlocs.Local;
					if(ret < loc)
						ret = loc;
				}
			}
			if(any_locals)
				return ret + 1;
			return ret;
		}
	}
}
